﻿#region Header
// ------------------------ Licence / Copyright ------------------------
// 
// ScrumTable for Scrum Meeting Support
// Copyright © HSR - Hochschule für Technik Rapperswil
// All Rights Reserved
// 
// Author:
//  Michael Gfeller Silvan Gehrig Patrick Boos
// 
// ---------------------------------------------------------------------
#endregion

#region Usings

using System;
using System.Collections.Generic;
using ScrumTable.Common;
using ScrumTable.DL.Data.Common.Properties;
using ScrumTable.DL.Data.Schema;

#endregion

namespace ScrumTable.DL.Data.Common
{
    /// <summary>
    /// Contains the store and restore facilities for a DataObjectState.
    /// </summary>
    public class DataObjectStateLoader
    {
        #region Declarations
        //--------------------------------------------------------------------
        // Declarations
        //--------------------------------------------------------------------

        #endregion

        #region Properties
        //--------------------------------------------------------------------
        // Properties
        //--------------------------------------------------------------------

        #endregion

        #region Constructors / Destructor
        //--------------------------------------------------------------------
        // Constructors / Destructor
        //--------------------------------------------------------------------

        /// <summary>
        /// Creates a new DataObjectStateLoader instance.
        /// </summary>
        public DataObjectStateLoader()
        {
        }

        #endregion

        #region Methods
        //--------------------------------------------------------------------
        // Methods
        //--------------------------------------------------------------------

        /// <summary>
        /// Restores the state stored in the current object into the given
        /// data object.
        /// </summary>
        /// <param name="dataToFill">Data object to fill with the current state data.</param>
        /// <param name="data">Specfies the stored data object which contains the data to fill.</param>
        /// <param name="beforeValueSet">Specifies the action which should be executed before a value is stored back to the data object.</param>
        /// <param name="afterValueSet">Specifies the action which should be executed after a value is stored back to the data object.</param>
        public void SaveStateTo(IDataObject dataToFill, IDataObjectState data, Action<SchemaBase> beforeValueSet, Action<SchemaBase> afterValueSet)
        {
            PreCondition.AssertNotNull(dataToFill, "dataToFill");
            PreCondition.AssertNotNull(data, "data");

            if (data.Schema != dataToFill.Schema)
            {
                throw new InvalidOperationException(string.Format(
                    Resources.LogDataStateLoaderSchemaInconsistency,
                    data.Schema,
                    data.Id,
                    dataToFill.Schema,
                    dataToFill.Id));
            }

            foreach (string valueName in data.State.Keys)
            {
                SchemaBase schemaEntry = data.Schema[valueName];

                if (schemaEntry.IsSchemaElementReadOnly)
                {
                    continue;
                }

                object valueOld = dataToFill[schemaEntry.SchemaName];
                object valueNew = data.State[schemaEntry.SchemaName];

                if (valueOld != valueNew && !Equals(valueOld, valueNew))
                {
                    if (beforeValueSet != null) beforeValueSet(schemaEntry);
                    dataToFill[schemaEntry.SchemaName] = valueNew;
                    if (afterValueSet != null) afterValueSet(schemaEntry);
                }
            }
        }

        /// <summary>
        /// Restores the state stored in the current object into the given
        /// data object.
        /// </summary>
        /// <param name="dataToFill">Data object to fill with the current state data.</param>
        /// <param name="data">Specfies the stored data object which contains the data to fill.</param>
        public void SaveStateTo(IDataObject dataToFill, IDataObjectState data)
        {
            SaveStateTo(dataToFill, data, null, null);
        }

        /// <summary>
        /// Restores the state stored in the current object into the given
        /// data object. This procedure will store all data from the given
        /// data object into the state.
        /// </summary>
        /// <param name="data">Data object to fill with the current state data.</param>
        public IDataObjectState LoadStateFrom(IDataObject data)
        {
            PreCondition.AssertNotNull(data, "data");

            DataObjectState state = new DataObjectState(data, data.Schema);

            foreach (SchemaBase schemaEntry in data.Schema.Schemata)
            {
                if (schemaEntry.IsSchemaElementReadOnly)
                {
                    continue;
                }
                state.State[schemaEntry.SchemaName] = data[schemaEntry.SchemaName];
            }
            return state;
        }

        /// <summary>
        /// Restores the state stored in the current object into the given
        /// data object. This procedure will store only the fields given
        /// in the value names list into the state.
        /// </summary>
        /// <param name="data">Data object to fill with the current state data.</param>
        /// <param name="valueNamesToExport">Specifies a list of value names which should be exported.</param>
        public IDataObjectState LoadStateFrom(IDataObject data, IList<string> valueNamesToExport)
        {
            PreCondition.AssertNotNull(data, "data");
            PreCondition.AssertNotNull(valueNamesToExport, "valueNamesToExport");

            DataObjectState state = new DataObjectState(data, data.Schema);

            foreach (string valueName in valueNamesToExport)
            {
                SchemaBase schemaEntry = data.Schema[valueName];

                if (schemaEntry.IsSchemaElementReadOnly)
                {
                    continue;
                }
                state.State[schemaEntry.SchemaName] = data[schemaEntry.SchemaName];
            }
            return state;
        }

        #endregion

        #region Events
        //--------------------------------------------------------------------
        // Events
        //--------------------------------------------------------------------

        #endregion
    }
}